home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / hypercrd / xcmds / tffdsply.hqx / tiffinfo.c < prev    next >
Text File  |  1993-01-04  |  27KB  |  1,137 lines

  1. /*
  2.  * This software is copyright 1992 by Robert Morris.
  3.  * You may freely redistribute this software as shareware
  4.  * if you do so in the same form as you got it. If you find
  5.  * this software useful, please send $12 to:
  6.  *   Robert Morris
  7.  *   P.O. Box 1044
  8.  *   Harvard Square Station
  9.  *   Cambridge, MA 02238
  10.  *   ecognome@aol.com
  11.  * If you incorporate any of this software in any kind of
  12.  * commercial product, please send $2 per copy distributed
  13.  * to the above address.
  14.  */
  15.  
  16. /*
  17.  * manipulate TIFF files.
  18.  */
  19. #include "tiffinfo.h"
  20. #include "string.h"
  21.  
  22. #ifdef TIFF_PRINTFS
  23. #include <stdio.h>
  24. #endif
  25.  
  26. void TIFFError(TIFFPtr, OSErr, StringPtr);
  27. long ttohs(TIFFPtr, short);
  28. long ttohl(TIFFPtr, long);
  29. OSErr tiff_read(TIFFPtr, unsigned long, void *, long);
  30. OSErr ScanTIFFDirectory(TIFFPtr);
  31. OSErr ReadTIFFEntry(TIFFPtr, long offset, struct TIFFEntry *);
  32. long ParseScalar(TIFFPtr, struct TIFFEntry *);
  33. long *ParseArray(TIFFPtr, struct TIFFEntry *);
  34. CTabHandle TranslateColorMap(long *colorMap, int ncolors);
  35. CTabHandle MakeGrayTable(int depth, int zeroIsWhite);
  36. Ptr ThreeToFour(Ptr in, long nPixels);
  37. long RowBytes(TIFFPtr);
  38. void CopyPMStrip(PixMapHandle pm, Rect sr, Rect dr, int dither);
  39. void CopyBMStrip(BitMap *, Rect sr, Rect dr, int inv);
  40. void UnDifference(Ptr p, long rowbytes, long nrows, long span);
  41.  
  42. /*
  43.  * Scan a TIFF file's fields to ferret out interesting information.
  44.  * Returns a TIFFPtr whether it succeeded or failed; the caller must
  45.  * call GetTIFFError() to distinguish.
  46.  */
  47. TIFFPtr
  48. ScanTIFF(int ref)
  49. {
  50.     struct TIFFHeader header;
  51.     TIFFPtr ti;
  52.     
  53.     ti = (TIFFPtr) NewPtr(sizeof(*ti));
  54.     if(ti == 0)
  55.         return(0);
  56.     memset(ti, 0, sizeof(*ti)); /* clear the record */
  57.     
  58.     ti->ref = ref;
  59.     
  60.     if(tiff_read(ti, 0L, &header, sizeof(header)) != 0)
  61.         return(ti);
  62.     
  63.     ti->byteOrder = header.byteOrder;
  64.     if((ti->byteOrder != BigEndian && ti->byteOrder != LittleEndian) ||
  65.        ttohs(ti, header.versionNumber) != 42){
  66.            TIFFError(ti, -1, "\pNot a TIFF file.");
  67.         return(ti);
  68.     }
  69.     
  70.     ti->offset = ttohl(ti, header.offset);
  71.     ScanTIFFDirectory(ti);
  72.     
  73.     return(ti);
  74. }
  75.  
  76. void
  77. DisposeTIFF(TIFFPtr ti)
  78. {
  79.     if(ti){
  80.         if(ti->bitsPerSample)
  81.             DisposPtr(ti->bitsPerSample);
  82.         ti->bitsPerSample = 0;
  83.         if(ti->colorMap)
  84.             DisposCTable(ti->colorMap);
  85.         ti->colorMap = 0;
  86.         if(ti->stripOffsets)
  87.             DisposPtr(ti->stripOffsets);
  88.         ti->stripOffsets = 0;
  89.         if(ti->stripByteCounts)
  90.             DisposPtr(ti->stripByteCounts);
  91.         ti->stripByteCounts = 0;
  92.         DisposPtr(ti);
  93.     }
  94. }
  95.  
  96. OSErr
  97. ScanTIFFDirectory(TIFFPtr ti)
  98. {
  99.     unsigned short nentries, entryno;
  100.     struct TIFFEntry entry;
  101.     long nextoffset, n, i, offset, *colorMap = 0;
  102.     OSErr err;
  103.     
  104.     offset = ti->offset;
  105.     ti->err = 0;
  106.     
  107.     /* assign default values */
  108.     ti->bitsPerSample = (long *) NewPtr(sizeof(long));
  109.     if(ti->bitsPerSample == 0){
  110.         TIFFError(ti, err = MemError(), "\pOut of memory");
  111.         return(err);
  112.     }
  113.     ti->bitsPerSample[0] = 1;
  114.     ti->colorMap = 0;
  115.     ti->compression = NoCompression;
  116.     ti->predictor = NoPredictor;
  117.     ti->imageLength = -1;
  118.     ti->imageWidth = -1;
  119.     ti->photometricInterpretation = -1;
  120.     ti->planarConfiguration = PCContiguous;
  121.     ti->rowsPerStrip = 0x7fffffff;
  122.     ti->samplesPerPixel = 1;
  123.     ti->stripByteCounts = 0;
  124.     ti->stripOffsets = 0;    
  125.     
  126.     if((err = tiff_read(ti, ti->offset, &nentries, sizeof(nentries))) != 0)
  127.         return(err);
  128.     offset += sizeof(nentries);
  129.     nentries = ttohs(ti, nentries);
  130.     
  131. #define ZAP(x) {if(x){DisposPtr(x);} x = 0;} 
  132.     
  133.     for(entryno = 0; entryno < nentries; entryno++){
  134.         if((err = ReadTIFFEntry(ti, offset, &entry)) != 0)
  135.             return(err);
  136.         offset += sizeof(entry);
  137.         
  138.         switch(entry.tag){
  139.         case ImageWidth:
  140.             ti->imageWidth = ParseScalar(ti, &entry);
  141.             break;
  142.         case ImageLength:
  143.             ti->imageLength = ParseScalar(ti, &entry);
  144.             break;
  145.         case BitsPerSample:
  146.             ZAP(ti->bitsPerSample);
  147.             ti->bitsPerSample = ParseArray(ti, &entry);
  148.             break;
  149.         case ColorMap:
  150.             if(ti->colorMap)
  151.                 DisposCTable(ti->colorMap);
  152.             ti->colorMap = 0;
  153.             colorMap = ParseArray(ti, &entry);
  154.             if(colorMap){
  155.                 ti->colorMap = TranslateColorMap(colorMap, entry.length / 3);
  156.                 DisposPtr(colorMap);
  157.                 colorMap = 0;
  158.                 if(ti->colorMap == 0)
  159.                     TIFFError(ti, -1, "\pCould not make color map.");
  160.             }
  161.             break;
  162.         case Compression:
  163.             ti->compression = ParseScalar(ti, &entry);
  164.             break;
  165.         case Predictor:
  166.             ti->predictor = ParseScalar(ti, &entry);
  167.             break;
  168.         case PhotometricInterpretation:
  169.             ti->photometricInterpretation = ParseScalar(ti, &entry);
  170.             break;
  171.         case StripByteCounts:
  172.             ZAP(ti->stripByteCounts);
  173.             ti->stripByteCounts = ParseArray(ti, &entry);
  174.             break;
  175.         case StripOffsets:
  176.             ZAP(ti->stripOffsets);
  177.             ti->stripOffsets = ParseArray(ti, &entry);
  178.             break;
  179.         case SamplesPerPixel:
  180.             ti->samplesPerPixel = ParseScalar(ti, &entry);
  181.             break;
  182.         case RowsPerStrip:
  183.             ti->rowsPerStrip = ParseScalar(ti, &entry);
  184.             break;
  185.         case PlanarConfiguration:
  186.             ti->planarConfiguration = ParseScalar(ti, &entry);
  187.             break;
  188. #ifdef TIFF_PRINTFS
  189.         default:
  190.             printf("tag %d, type %d, length %ld, value %ld/0x%lx\n",
  191.                 entry.tag, entry.type, entry.length, entry.offset, entry.offset);
  192. #endif
  193.         }
  194.     }
  195.     
  196.     /* Some NeXT program generates bogus PlanarConfigurations of 2. */
  197.     if(ti->samplesPerPixel == 1 && ti->planarConfiguration == 2)
  198.         ti->planarConfiguration = 1;
  199.     
  200.     if(ti->rowsPerStrip > ti->imageLength)
  201.         ti->rowsPerStrip = ti->imageLength;
  202.     ti->stripsPerImage = (ti->imageLength + ti->rowsPerStrip - 1) / ti->rowsPerStrip;
  203.  
  204.     /*
  205.      * We need a color map for gray-scale images deeper than one bit.
  206.      */
  207.     if(ti->colorMap == 0 &&
  208.        ti->samplesPerPixel == 1 &&
  209.        ti->bitsPerSample[0] <= 8 &&
  210.        ti->bitsPerSample[0] > 1 &&
  211.        (ti->photometricInterpretation == PIZeroIsWhite ||
  212.         ti->photometricInterpretation == PIZeroIsBlack)){
  213.         ti->colorMap = MakeGrayTable(ti->bitsPerSample[0],
  214.                                      ti->photometricInterpretation == PIZeroIsWhite);
  215.         if(ti->colorMap == 0)
  216.             TIFFError(ti, -1, "\pCould not make gray-scale color map.");
  217.     }
  218.         
  219.     tiff_read(ti, offset, &nextoffset, sizeof(nextoffset));
  220.     ti->nextOffset = ttohl(ti, nextoffset);
  221.     
  222.     return(0);
  223. }
  224.  
  225. /*
  226.  * returns 0 if OK, or a negative error #.
  227.  */
  228. OSErr
  229. ReadTIFFEntry(TIFFPtr ti, long offset, struct TIFFEntry *ep)
  230. {
  231.     OSErr err;
  232.     
  233.     if((err = tiff_read(ti, offset, ep, sizeof(struct TIFFEntry))) != 0)
  234.         return(err);
  235.     ep->tag = ttohs(ti, ep->tag);
  236.     ep->type = ttohs(ti, ep->type);
  237.     ep->length = ttohl(ti, ep->length);
  238.     return(0);
  239. }
  240.  
  241. /*
  242.  * tries to interpret an entry as a single 32-bit integer value.
  243.  * can handle either TIFF_SHORT or TIFF_LONG.
  244.  * assumes ReadTIFFEntry() has already adjusted byte order of tag, type, and length.
  245.  * returns 0 if OK, or a negative error #.
  246.  * On the Mac, values appear in the highest bits of offset.
  247.  */
  248. long
  249. ParseScalar(TIFFPtr ti, struct TIFFEntry *ep)
  250. {
  251.     if(ep->length != 1)
  252.         return(-1);
  253.     if(ep->type == TIFF_BYTE){
  254.         return((ep->offset >> 24) & 0xff);
  255.     } else if(ep->type == TIFF_SHORT){
  256.         return(ttohs(ti, (ep->offset >> 16) & 0xffff));
  257.     } else if(ep->type == TIFF_LONG){
  258.         return(ttohl(ti, ep->offset));
  259.     } else {
  260.         TIFFError(ti, -1, "\pUnknown value type.");
  261.         return(-1);
  262.     }
  263. }
  264.  
  265. /*
  266.  * Returns an array of longs, no matter what the size of the array element.
  267.  * Note that if the array fits in the offset field, it will be there, in the
  268.  * high-order bits, with element zero highest.
  269.  */
  270. long *
  271. ParseArray(TIFFPtr ti, struct TIFFEntry *ep)
  272. {
  273.     long nbytes, i;
  274.     unsigned char *cp = 0;
  275.     unsigned short *sp = 0;
  276.     long *lp = 0;
  277.     
  278.     if(ep->length < 0)
  279.         goto bad;
  280.         
  281.     lp = (long *) NewPtr(ep->length * sizeof(long));
  282.     if(lp == 0)
  283.         goto bad;
  284.         
  285.     if(ep->type == TIFF_BYTE){
  286.         nbytes = ep->length;
  287.         if(nbytes <= 4){
  288.             for(i = 0; i < ep->length; i++)
  289.                 lp[i] = (ep->offset >> (24 - (i * 8))) & 0xff;
  290.         } else {
  291.             cp = (unsigned char *) NewPtr(nbytes);
  292.             if(cp == 0)
  293.                 goto bad;
  294.             if(tiff_read(ti, ttohl(ti, ep->offset), (char *)cp, nbytes) != 0)
  295.                 goto bad;
  296.             for(i = 0; i < ep->length; i++)
  297.                 lp[i] = cp[i];
  298.         }
  299.     } else if(ep->type == TIFF_SHORT){
  300.         nbytes = ep->length * 2;
  301.         if(nbytes <= 4){
  302.             for(i = 0; i < ep->length; i++)
  303.                 lp[i] = ttohs(ti, ep->offset >> (16 - (i * 16)));
  304.         } else {
  305.             sp = (unsigned short *) NewPtr(nbytes);
  306.             if(sp == 0)
  307.                 goto bad;
  308.             if(tiff_read(ti, ttohl(ti, ep->offset), (char *)sp, nbytes) != 0)
  309.                 goto bad;
  310.             for(i = 0; i < ep->length; i++)
  311.                 lp[i] = ttohs(ti, sp[i]);
  312.         }
  313.     } else if(ep->type == TIFF_LONG){
  314.         nbytes = ep->length * 4;
  315.         if(nbytes <= 4){
  316.             lp[0] = ttohl(ti, ep->offset);
  317.         } else {
  318.             if(tiff_read(ti, ttohl(ti, ep->offset), (char *)lp, nbytes) != 0)
  319.                 goto bad;
  320.             for(i = 0; i < ep->length; i++)
  321.                 lp[i] = ttohl(ti, lp[i]);
  322.         }
  323.     } else {
  324.         goto bad;
  325.     }
  326.     
  327.     if(cp)
  328.         DisposPtr(cp);
  329.     if(sp)
  330.         DisposPtr(sp);
  331.     return(lp);
  332.     
  333. bad:
  334.     TIFFError(ti, -1, "\pInvalid array field.");
  335.     if(cp)
  336.         DisposPtr(cp);
  337.     if(sp)
  338.         DisposPtr(sp);
  339.     if(lp)
  340.         DisposPtr(lp);
  341.     return(0);
  342. }
  343.  
  344. /* convert depth (<= 8) to # of colors */
  345. int ColorsOfDepth[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 };
  346.  
  347. /*
  348.  * return a color map with ngrays shades of gray in it.
  349.  */
  350. CTabHandle
  351. MakeGrayTable(int depth, int zeroIsWhite)
  352. {
  353.     int i, ncolors;
  354.     CTabHandle cth;
  355.     RGBColor rgb;
  356.     
  357.     if(HasColorQD() == 0)
  358.         return(0);
  359.         
  360.     if(depth >= 1 && depth <= 8)
  361.         ncolors = ColorsOfDepth[depth];
  362.     else
  363.         return(0);
  364.         
  365.     cth = (CTabHandle) NewHandle((ncolors * sizeof(ColorSpec)) + 10);
  366.     if(cth == 0)
  367.         return(0);
  368.         
  369.     (*cth)->ctSeed = GetCTSeed();
  370.     (*cth)->ctFlags = 0;
  371.     (*cth)->ctSize = ncolors - 1;
  372.     
  373.     if(zeroIsWhite){
  374.         for(i = 0; i < ncolors; i++){
  375.             rgb.red = rgb.green = rgb.blue = (65535 / (ncolors - 1)) * (ncolors - i - 1);
  376.             (*cth)->ctTable[i].value = i; /* this must be filled in... */
  377.             (*cth)->ctTable[i].rgb = rgb;
  378.         }
  379.     } else {
  380.         /* this doesn't work so hot on the Mac */
  381.         for(i = 0; i < ncolors; i++){
  382.             rgb.red = rgb.green = rgb.blue = (65535 / (ncolors - 1)) * i;
  383.             (*cth)->ctTable[i].value = i; /* this must be filled in... */
  384.             (*cth)->ctTable[i].rgb = rgb;
  385.         }
  386.     }
  387.     
  388.     return(cth);
  389. }
  390.  
  391. /*
  392.  * Turn a TIFF color table, which has red values, then green values, then blue values,
  393.  * into a QuickDraw ColorTable.
  394.  */
  395. CTabHandle
  396. TranslateColorMap(long *colorMap, int ncolors)
  397. {
  398.     int i;
  399.     CTabHandle cth;
  400.     RGBColor rgb;
  401.     
  402.     if(HasColorQD() == 0)
  403.         return(0);
  404.         
  405.     if(colorMap == 0 || ncolors <= 0 || ncolors > 256)
  406.         return(0);
  407.         
  408.     cth = (CTabHandle) NewHandle((ncolors * sizeof(ColorSpec)) + 10);
  409.     if(cth == 0)
  410.         return(0);
  411.         
  412.     (*cth)->ctSeed = GetCTSeed();
  413.     (*cth)->ctFlags = 0;
  414.     (*cth)->ctSize = ncolors - 1;
  415.     
  416.     for(i = 0; i < ncolors; i++){
  417.         rgb.red = colorMap[i];
  418.         rgb.green = colorMap[i + ncolors];
  419.         rgb.blue = colorMap[i + ncolors + ncolors];
  420.         (*cth)->ctTable[i].value = i; /* this must be filled in... */
  421.         (*cth)->ctTable[i].rgb = rgb;
  422.     }
  423.     
  424.     return(cth);
  425.  
  426. }
  427.  
  428. long
  429. ttohs(TIFFPtr ti, short s)
  430. {
  431.     long s1;
  432.     
  433.     if(ti->byteOrder == BigEndian){
  434.         /* Mac-order */
  435.         return(s & 0xffff);
  436.     } else {
  437.         s1 = (s >> 8) & 0xff;
  438.         s1 |= (s & 0xff) << 8;
  439.         return(s1);
  440.     }
  441. }
  442.  
  443. long
  444. ttohl(TIFFPtr ti, long l)
  445. {
  446.     long l1;
  447.     int i;
  448.     
  449.     if(ti->byteOrder == BigEndian){
  450.         /* Mac-order */
  451.         return(l);
  452.     } else {
  453.         l1 = 0;
  454.         for(i = 0; i < 4; i++){
  455.             l1 <<= 8;
  456.             l1 |= (l & 0xff);
  457.             l >>= 8;
  458.         }
  459.         return(l1);
  460.     }
  461. }
  462.  
  463. OSErr
  464. tiff_read(TIFFPtr ti, unsigned long offset, void *buf, long n)
  465. {
  466.     int err;
  467.     long count;
  468.     
  469.     err = SetFPos(ti->ref, fsFromStart, offset);
  470.     if(err < 0){
  471.         TIFFError(ti, err, "\pSeek failed.");
  472.         return(err);
  473.     }
  474.         
  475.     count = n;
  476.     err = FSRead(ti->ref, &count, buf);
  477.     if(err < 0 && err != eofErr){
  478.         TIFFError(ti, err, "\pRead failed.");
  479.         return(err);
  480.     }
  481.     if(count != n){
  482.         TIFFError(ti, -1, "\pRead returned too little data.");
  483.         return(eofErr);
  484.     }
  485.         
  486.     return(0);
  487. }
  488.  
  489. PixMapHandle
  490. PalettePixMap(short depth, CTabHandle cth, long x, long y, long width, long height,
  491.               Ptr data, long row)
  492. {
  493.     PixMapHandle pm;
  494.     
  495.     if(HasColorQD() == 0)
  496.         return(0);
  497.         
  498.     /* Enforce restrictions. */
  499.     if((row & 1) != 0 ||
  500.        (((long) data) & 1) != 0 ||
  501.        (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
  502.        cth == 0){
  503.            return(0);
  504.     }
  505.     
  506.     pm = NewPixMap();
  507.     if(pm == 0)
  508.         return(0);
  509.         
  510.     (*pm)->pmVersion = 0; /* this is crucial */
  511.     (*pm)->pmReserved = 0;
  512.     (*pm)->packType = 0;
  513.     (*pm)->packSize = 0;
  514.     (*pm)->pixelType = 0; /* chunky */
  515.     (*pm)->pixelSize = depth; /* bits per pixel */
  516.     (*pm)->cmpCount = 1; /* 1 component per pixel */
  517.     (*pm)->cmpSize = depth; /* bits per component */
  518.     (*pm)->planeBytes = 0;
  519.     
  520.     (*pm)->bounds.left = x;
  521.     (*pm)->bounds.right = x + width;
  522.     (*pm)->bounds.top = y;
  523.     (*pm)->bounds.bottom = y + height;
  524.     
  525.     (*pm)->baseAddr = data;
  526.     (*pm)->rowBytes = row | 0x8000; /* the 0x8000 marks this as a Pixmap, not Bitmap */
  527.     
  528.     if((*pm)->pmTable == 0){
  529.         DisposPixMap(pm);
  530.         return(0);
  531.     }
  532.         
  533.     /*
  534.      * Give the PixMap its own color table, which DisposPixMap() frees.
  535.      */
  536.     MoveHHi(cth);
  537.     HLock(cth);
  538.     PtrToXHand(*cth, (*pm)->pmTable, GetHandleSize(cth));
  539.     HUnlock(cth);
  540.     
  541.     return(pm);
  542. }
  543.  
  544. PixMapHandle
  545. RGBPixMap(short depth, long x, long y, long width, long height,
  546.           Ptr data, long rowbytes)
  547. {
  548.     PixMapHandle pm;
  549.     
  550.     if(HasQD32() == 0)
  551.         return(0);
  552.         
  553.     /* Enforce restrictions. */
  554.     if((rowbytes & 1) != 0 ||
  555.        (((long) data) & 1) != 0 ||
  556.        (depth != 16 && depth != 32)){
  557.            return(0);
  558.     }
  559.     
  560.     pm = NewPixMap();
  561.     if(pm == 0)
  562.         return(0);
  563.         
  564.     (*pm)->pmVersion = 0; /* this is crucial */
  565.     (*pm)->pmReserved = 0;
  566.     (*pm)->packType = 0;
  567.     (*pm)->packSize = 0;
  568.     (*pm)->pixelType = 16; /* RGBDirect */
  569.     (*pm)->pixelSize = depth; /* bits per pixel */
  570.     (*pm)->cmpCount = 3; /* 1 component per pixel */
  571.     (*pm)->cmpSize = (depth == 32 ? 8 : 5); /* bits per component */
  572.     (*pm)->planeBytes = 0;
  573.     
  574.     (*pm)->bounds.left = x;
  575.     (*pm)->bounds.right = x + width;
  576.     (*pm)->bounds.top = y;
  577.     (*pm)->bounds.bottom = y + height;
  578.     
  579.     (*pm)->baseAddr = data;
  580.     (*pm)->rowBytes = rowbytes | 0x8000; /* the 0x8000 marks this as a Pixmap, not Bitmap */
  581.     
  582.     return(pm);
  583. }
  584.  
  585. /*
  586.  * Return (a*b)/c. Try to minimize the error.
  587.  */
  588. #define MulDiv(a, b, c) (((a) * (b)) / (c))
  589.  
  590. /*
  591.  * Convert a from coordinate world aref to world bref. Result in b.
  592.  * Optimized for aref and bref the same size.
  593.  */
  594. void
  595. ScaleRect(Rect *aref, Rect *a, Rect *bref, Rect *b)
  596. {
  597.     long hmul, hdiv, hoff;
  598.     long vmul, vdiv, voff;
  599.     
  600.     hmul = bref->right - bref->left;
  601.     hdiv = aref->right - aref->left;
  602.     
  603.     hoff = bref->left - MulDiv(aref->left, hmul, hdiv);
  604.     
  605.     vmul = bref->bottom - bref->top;
  606.     vdiv = aref->bottom - aref->top;
  607.     
  608.     voff = bref->top - MulDiv(aref->top, vmul, vdiv);
  609.     
  610.     b->left = MulDiv(a->left, hmul, hdiv) + hoff;
  611.     b->right = MulDiv(a->right, hmul, hdiv) + hoff;
  612.     b->top = MulDiv(a->top, vmul, vdiv) + voff;
  613.     b->bottom = MulDiv(a->bottom, vmul, vdiv) + voff;
  614. }
  615.  
  616. /*
  617.  * Calculate how many (uncompressed) bytes in a scanline.
  618.  * Doesn't work for separated planes.
  619.  * Returns -1 on error.
  620.  */
  621. long
  622. RowBytes(TIFFPtr ti)
  623. {
  624.     long rowbytes;
  625.     
  626.     if(ti->planarConfiguration != PCContiguous){
  627.         TIFFError(ti, -1, "\pCannot understand planar data.");
  628.         return(-1);
  629.     }
  630.         
  631.     rowbytes = (ti->bitsPerSample[0] * ti->samplesPerPixel * ti->imageWidth + 7) / 8;
  632.     
  633.     return(rowbytes);
  634. }
  635.  
  636. /*
  637.  * Read a reasonable number of scan lines from an image, uncompress them if
  638.  * necessary, and return a new pointer to the data. For compressed images,
  639.  * this routine always reads exactly one strip. Since some applications write
  640.  * large uncompressed images as a single strip, this routine tries to read
  641.  * only about 64K at a time. ReadStrip() returns the number of lines actually
  642.  * read in *linesread, and the first line actually read in *firstread. The
  643.  * latter will always be <= startline.
  644.  */
  645. Ptr
  646. ReadStrip(TIFFPtr ti, long startline, long *firstread, long *linesread)
  647. {
  648.     long count, rowbytes, offset, uncount, i, nrows, strip;
  649.     long skip, suboffset;
  650.     Ptr p = 0, p1 = 0;
  651.     Ptr srcPtr, dstPtr;
  652.     
  653.     /*
  654.      * Decide which strip to read.
  655.      */
  656.     for(strip = 0; strip < ti->stripsPerImage; strip++)
  657.         if(startline >= strip*ti->rowsPerStrip && startline < (strip+1)*ti->rowsPerStrip)
  658.             break;
  659.     if(strip >= ti->stripsPerImage){
  660.         TIFFError(ti, -1, "\pBad arg to ReadStrip()");
  661.         return(0);
  662.     }
  663.     
  664.     /*
  665.      * Decide how many rows in this strip; the last strip might have
  666.      * fewer than the others.
  667.      */
  668.     nrows = ti->rowsPerStrip;
  669.     if((strip * ti->rowsPerStrip) + nrows > ti->imageLength)
  670.         nrows = ti->imageLength - (strip * ti->rowsPerStrip);
  671.     
  672.     if(ti->stripOffsets == 0){
  673.         TIFFError(ti, -1, "\pNo strip offsets.");
  674.         return(0);
  675.     }
  676.     offset = ti->stripOffsets[strip];
  677.     
  678.     if(ti->compression == NoCompression){
  679.         /*
  680.          * Just read part of a strip.
  681.          */
  682.         if((rowbytes = RowBytes(ti)) == -1)
  683.             return(0);
  684.         skip = startline - (strip * ti->rowsPerStrip);
  685.         suboffset = offset + (skip * rowbytes);
  686.         nrows -= skip;
  687. #define BUFSIZE 64000L
  688.         if(rowbytes >= BUFSIZE){
  689.             nrows = 1;
  690.         } else if((nrows * rowbytes) > BUFSIZE){
  691.             nrows = BUFSIZE / rowbytes;
  692.         }
  693.         count = rowbytes * nrows;
  694.     
  695.         p = NewPtr(count);
  696.         if(p == 0){
  697.             TIFFError(ti, MemError(), "\pOut of memory.");
  698.             return(0);
  699.         }
  700.     
  701.         if(tiff_read(ti, suboffset, p, count) != 0)
  702.             goto bad;
  703.             
  704.         *firstread = startline;
  705.         *linesread = nrows;
  706.         
  707.         return(p);
  708.     }
  709.         
  710.     if(ti->stripByteCounts){
  711.         count = ti->stripByteCounts[strip];
  712.     } else {
  713.         /* cannot guess strip length */
  714.         return(0);
  715.     }        
  716.     
  717.     p = NewPtr(count);
  718.     if(p == 0){
  719.         TIFFError(ti, MemError(), "\pOut of memory.");
  720.         return(0);
  721.     }
  722.  
  723.     if(tiff_read(ti, offset, p, count) != 0)
  724.         goto bad;
  725.     
  726.     if(ti->compression == LZWCompression){
  727.         rowbytes = RowBytes(ti);
  728.         if(rowbytes == -1)
  729.             goto bad;
  730.         uncount = rowbytes * ti->rowsPerStrip;
  731.         p1 = NewPtr(uncount);
  732.         if(p1 == 0){
  733.             TIFFError(ti, MemError(), "\pOut of memory.");
  734.             goto bad;
  735.         }
  736.         
  737.         if(UnLZW(p, count, p1, uncount) != 0){
  738.             TIFFError(ti, -1, "\pLZW decompression failed.");
  739.             goto bad;
  740.         }
  741.         DisposPtr(p);
  742.         p = p1;
  743.         p1 = 0;
  744.         
  745.         if(ti->predictor == HDPredictor &&
  746.            ti->bitsPerSample[0] == 8 &&
  747.            ti->planarConfiguration == PCContiguous){
  748.             /* horizontal differencing */
  749.             for(i = 0; i < ti->samplesPerPixel; i++)
  750.                 UnDifference(p+i, rowbytes, ti->rowsPerStrip, ti->samplesPerPixel);
  751.         } else if(ti->predictor != NoPredictor){
  752.             TIFFError(ti, -1, "\pUnimplemented LZW prediction type.");
  753.             goto bad;
  754.         }
  755.     } else if(ti->compression == PackCompression){
  756.         rowbytes = RowBytes(ti);
  757.         if(rowbytes == -1)
  758.             goto bad;
  759.         if(rowbytes > 32767){
  760.             TIFFError(ti, -1, "\pRow too long for UnpackBits.");
  761.             goto bad;
  762.         }
  763.         uncount = rowbytes * ti->rowsPerStrip;
  764.         p1 = NewPtr(uncount);
  765.         if(p1 == 0){
  766.             TIFFError(ti, MemError(), "\pOut of memory.");
  767.             goto bad;
  768.         }
  769.         srcPtr = p;
  770.         for(i = 0; i < nrows; i++){
  771.             dstPtr = p1 + (i * rowbytes);
  772.             /* does UnpackBits restrict the size of rowbytes? */
  773.             UnpackBits(&srcPtr, &dstPtr, (int)rowbytes);
  774.         }
  775.         DisposPtr(p);
  776.         p = p1;
  777.         p1 = 0;
  778.     } else {
  779.         TIFFError(ti, -1, "\pUnimplemented compression type.");
  780.         goto bad;
  781.     }
  782.     
  783.     *firstread = strip * ti->rowsPerStrip;
  784.     *linesread = nrows;
  785.     
  786.     return(p);
  787.     
  788. bad:
  789.     if(p)
  790.         DisposPtr(p);
  791.     if(p1)
  792.         DisposPtr(p1);
  793.     return(0);
  794. }
  795.  
  796. /*
  797.  * Draw a tiff file image in the current QuickDraw port.
  798.  * The idea is to read each strip, convert into a form
  799.  * that's usable as a QuickDraw PixMap, and copy it to the
  800.  * current port. As an optimization, don't bother reading
  801.  * strips that won't be visible.
  802.  */
  803. OSErr
  804. DrawTIFF(int ref, TIFFPtr ti, Rect sr, Rect dr, int dither)
  805. {
  806.     long y, stripHeight, dstStripHeight, i, rowbytes;
  807.     Ptr p = 0, p1;
  808.     PixMapHandle pm = 0;
  809.     Rect visr, portr;
  810.     GrafPtr port;
  811.     int ppb, inv;
  812.     BitMap bm;
  813.     
  814.     GetPort(&port);
  815.     
  816.     /*
  817.      * Make sure we know how many bits there are per sample, and that
  818.      * the Red, Green, and Blue channels are the same size for RGB images.
  819.      */
  820.     if(ti->bitsPerSample == 0){
  821.         TIFFError(ti, -1, "\pNo bits-per-sample given.");
  822.         return(-1);
  823.     }
  824.     for(i = 1; i < ti->samplesPerPixel; i++){
  825.         if(ti->bitsPerSample[i] != ti->bitsPerSample[i-1]){
  826.             TIFFError(ti, -1, "\pBits-per-sample are different.");
  827.             return(-1);
  828.         }
  829.     }
  830.     
  831.     ti->ref = ref;
  832.     
  833.     /*
  834.      * The destination rectangle may not be totally visible. As an optimization,
  835.      * translate the bounding box of the visible area into the source image
  836.      * space, and only copy the relevant strips.
  837.      */
  838.     portr = (*(port->visRgn))->rgnBBox;
  839.     ScaleRect(&dr, &portr, &sr, &visr);
  840.     y = visr.top;
  841.     stripHeight = 0;
  842.  
  843.     for( ; y < visr.bottom && y < ti->imageLength; y += stripHeight){
  844.         p = ReadStrip(ti, y, &y, &stripHeight);
  845.         if(p == 0)
  846.             goto bad;
  847.          
  848.         /*
  849.          * Find a way to draw the strip.
  850.          */
  851.         if(ti->samplesPerPixel == 1 &&
  852.            ti->bitsPerSample[0] == 1 &&
  853.            (ti->photometricInterpretation == PIZeroIsBlack ||
  854.             ti->photometricInterpretation == PIZeroIsWhite)){
  855.             rowbytes = (ti->bitsPerSample[0] * ti->imageWidth + 7) / 8;
  856.             inv = ti->photometricInterpretation == PIZeroIsBlack;
  857.             if(rowbytes & 1){
  858.                 bm.bounds.right = ti->imageWidth;
  859.                 bm.rowBytes = rowbytes + 1;
  860.                 for(i = 0; i < stripHeight; i++){
  861.                     p1 = p + (i * rowbytes);
  862.                     bm.bounds.top = y + i;
  863.                     bm.bounds.bottom = y + i + 1;
  864.                     if((long)p1 & 1){
  865.                         bm.bounds.left = -8;
  866.                         bm.baseAddr = p1 - 1;
  867.                     } else {
  868.                         bm.bounds.left = 0;
  869.                         bm.baseAddr = p1;
  870.                     }
  871.                     CopyBMStrip(&bm, sr, dr, inv);
  872.                 }
  873.             } else {
  874.                 bm.baseAddr = p;
  875.                 bm.rowBytes = rowbytes;
  876.                 bm.bounds.left = 0;
  877.                 bm.bounds.right = ti->imageWidth;
  878.                 bm.bounds.top = y;
  879.                 bm.bounds.bottom = y + stripHeight;
  880.                 CopyBMStrip(&bm, sr, dr, inv);
  881.             }            
  882.         } else if(ti->samplesPerPixel == 3 &&
  883.            ti->bitsPerSample[0] == 8 &&
  884.            ti->planarConfiguration == PCContiguous &&
  885.            ti->photometricInterpretation == PIRGB){
  886.             /* convert from 3 to 4 bytes per pixel */
  887.             p1 = ThreeToFour(p, ti->imageWidth * stripHeight);
  888.             if(p1 == 0){
  889.                 TIFFError(ti, -1, "\pOut of memory.");
  890.                 goto bad;
  891.             }
  892.             rowbytes = 4 * ti->imageWidth;
  893.             pm = RGBPixMap(32, 0, y, ti->imageWidth, stripHeight, p1, rowbytes);
  894.             if(pm == 0){
  895.                 DisposPtr(p1);
  896.                 TIFFError(ti, -1, "\pCould not allocate PixMap.");
  897.                 goto bad;
  898.             }
  899.             CopyPMStrip(pm, sr, dr, dither);
  900.             DisposPixMap(pm);
  901.             pm = 0;
  902.             DisposPtr(p1);
  903.         } else if(ti->samplesPerPixel == 1 &&
  904.            (ti->bitsPerSample[0] == 1 || ti->bitsPerSample[0] == 2 ||
  905.             ti->bitsPerSample[0] == 4 || ti->bitsPerSample[0] == 8) &&
  906.            (ti->photometricInterpretation == PIPalette ||
  907.             ti->photometricInterpretation == PIZeroIsBlack ||
  908.             ti->photometricInterpretation == PIZeroIsWhite)){
  909.             rowbytes = (ti->bitsPerSample[0] * ti->imageWidth + 7) / 8;
  910.             if(rowbytes & 1){
  911.                 /* must copy odd widths a line at a time */
  912.                 ppb = 8 / ti->bitsPerSample[0];
  913.                 pm = PalettePixMap(ti->bitsPerSample[0], ti->colorMap,
  914.                                    0, 0,
  915.                                    ti->imageWidth, 1,
  916.                                    0, rowbytes + 1);
  917.                 if(pm == 0){
  918.                     TIFFError(ti, -1, "\pCould not allocate PixMap.");
  919.                     goto bad;
  920.                 }
  921.                 for(i = 0; i < stripHeight; i++){
  922.                     p1 = p + (i * rowbytes);
  923.                     (*pm)->bounds.top = y + i;
  924.                     (*pm)->bounds.bottom = y + i + 1;
  925.                     if((long)p1 & 1){
  926.                         (*pm)->bounds.left = -ppb;
  927.                         (*pm)->baseAddr = p1 - 1;
  928.                     } else {
  929.                         (*pm)->bounds.left = 0;
  930.                         (*pm)->baseAddr = p1;
  931.                     }
  932.                     CopyPMStrip(pm, sr, dr, dither);
  933.                 }
  934.                 DisposPixMap(pm);
  935.                 pm = 0;
  936.             } else {
  937.                 pm = PalettePixMap(ti->bitsPerSample[0], ti->colorMap,
  938.                                    0, y,
  939.                                    ti->imageWidth, stripHeight,
  940.                                    p, rowbytes);
  941.                 if(pm == 0){
  942.                     TIFFError(ti, -1, "\pCould not allocate PixMap.");
  943.                     goto bad;
  944.                 }
  945.                 CopyPMStrip(pm, sr, dr, dither);
  946.                 DisposPixMap(pm);
  947.                 pm = 0;
  948.             }
  949.         } else {
  950.             TIFFError(ti, -1, "\pUnimplemented image representation.");
  951.             goto bad;
  952.         }        
  953.             
  954.         DisposPtr(p);
  955.         p = 0;
  956.     }
  957.     
  958.     return(0);
  959.     
  960. bad:
  961.     if(p)
  962.         DisposPtr(p);
  963.     if(pm)
  964.         DisposPixMap(pm);
  965.     return(-1);
  966. }
  967.  
  968. /*
  969.  * Copy a pixmap of a strip to the right place.
  970.  */
  971. void
  972. CopyPMStrip(PixMapHandle pm, Rect sr, Rect dr, int dither)
  973. {
  974.     Rect sr1, dr1;
  975.     GrafPtr port;
  976.  
  977.     sr1 = (*pm)->bounds;
  978.     sr1.left = sr.left;
  979.     sr1.right = sr.right;
  980.     if(sr1.top < sr.top)
  981.         sr1.top = sr.top;
  982.     if(sr1.bottom > sr.bottom)
  983.         sr1.bottom = sr.bottom;
  984.         
  985.     ScaleRect(&sr, &sr1, &dr, &dr1);
  986.     
  987.     GetPort(&port);
  988.     
  989.     MoveHHi(pm);
  990.     HLock(pm);
  991.     CopyBits(*pm, &(port->portBits), &sr1, &dr1, dither ? 64 : srcCopy, 0L);
  992.     HUnlock(pm);
  993. }
  994.  
  995. /*
  996.  * Copy a bitmap of a strip to the right place.
  997.  * Optionally invert black and white.
  998.  */
  999. void
  1000. CopyBMStrip(BitMap *bm, Rect sr, Rect dr, int inv)
  1001. {
  1002.     Rect sr1, dr1;
  1003.     GrafPtr port;
  1004.  
  1005.     sr1 = bm->bounds;
  1006.     sr1.left = sr.left;
  1007.     sr1.right = sr.right;
  1008.     if(sr1.top < sr.top)
  1009.         sr1.top = sr.top;
  1010.     if(sr1.bottom > sr.bottom)
  1011.         sr1.bottom = sr.bottom;
  1012.         
  1013.     ScaleRect(&sr, &sr1, &dr, &dr1);
  1014.     
  1015.     GetPort(&port);
  1016.     
  1017.     CopyBits(bm, &(port->portBits), &sr1, &dr1, inv ? notSrcCopy : srcCopy, 0L);
  1018. }
  1019.  
  1020.  
  1021. /*
  1022.  * Convert 3-bytes-per-pixel RGB data to 4-bytes-per-pixel, as required
  1023.  * for QuickDraw 32-bit Pix Maps. inLen is the number of bytes.
  1024.  */
  1025. Ptr
  1026. ThreeToFour(Ptr in, long nPixels)
  1027. {
  1028.     Ptr out;
  1029.     register unsigned long *inp, *outp;
  1030.     register unsigned long in1, in2, in3;
  1031.     char *ip, *op;
  1032.     
  1033.     out = NewPtr(4 * nPixels);
  1034.     if(out == 0)
  1035.         return(0);
  1036.         
  1037.     inp = (unsigned long *) in;
  1038.     outp = (unsigned long *) out;
  1039.     
  1040.     for( ; nPixels >= 4; nPixels -= 4){
  1041.         /* read 4 pixels worth of data in 4 longs: RGBR GBRG BRGB */
  1042.         in1 = *inp++;
  1043.         in2 = *inp++;
  1044.         in3 = *inp++;
  1045.         
  1046.         /* write the 4 pixels as 4 longs */
  1047.         *outp++ = in1 >> 8;
  1048.         *outp++ = ((in1 & 0xff) << 16) | ((in2 >> 16) & 0xffff);
  1049.         *outp++ = ((in2 & 0xffff) << 8) | (in3 >> 24);
  1050.         *outp++ = in3 & 0xffffff;
  1051.     }
  1052.     
  1053.     /* take care of last 1, 2 or 3 pixels one byte at a time */
  1054.     ip = (char *) inp;
  1055.     op = (char *) outp;
  1056.     for( ; nPixels > 0; --nPixels){
  1057.         *op++ = 0;
  1058.         *op++ = *ip++;
  1059.         *op++ = *ip++;
  1060.         *op++ = *ip++;
  1061.     }
  1062.     
  1063.     return(out);
  1064. }
  1065.  
  1066. /*
  1067.  * Un-difference a strip of image. Must be 8-bit samples.
  1068.  * Span indicates how many bytes to skip (for interleaved RGB).
  1069.  * Modifies the data in place.
  1070.  */
  1071. void
  1072. UnDifference(Ptr p, long rowbytes, long nrows, long span)
  1073. {
  1074.     long row, col, off;
  1075.     
  1076.     for(row = 0; row < nrows; row++){
  1077.         off = row * rowbytes;
  1078.         for(col = span; col < rowbytes; col += span){
  1079.             p[off + col] += p[off + col - span];
  1080.         }
  1081.     }
  1082. }
  1083.  
  1084. /*
  1085.  * Register an error with a TIFF record, for later retrieval with GetTIFFError().
  1086.  */
  1087. void
  1088. TIFFError(TIFFPtr ti, OSErr err, StringPtr p)
  1089. {
  1090.     int i;
  1091.     
  1092.     if(ti && ti->err == 0){
  1093.         if(err == 0)
  1094.             err = -1;
  1095.         ti->err = err;
  1096.         for(i = 0; i < p[0] && i < 255; i++)
  1097.             ti->errStr[i+1] = p[i+1];
  1098.         ti->errStr[0] = p[0];
  1099.     }
  1100. }
  1101.  
  1102. /*
  1103.  * Return and clear the error associated with a TIFF record.
  1104.  */
  1105. OSErr
  1106. GetTIFFError(TIFFPtr ti, StringPtr p)
  1107. {
  1108.     int i;
  1109.     OSErr err;
  1110.     
  1111.     p[0] = 0;
  1112.     if(ti == 0)
  1113.         return(-1);
  1114.         
  1115.     p[0] = ti->errStr[0];
  1116.     for(i = 0; i < p[0] && i < 255; i++)
  1117.         p[i+1] = ti->errStr[i+1];
  1118.         
  1119.     err = ti->err;
  1120.     ti->err = 0;
  1121.     ti->errStr[0] = 0;
  1122.     
  1123.     return(err);
  1124. }
  1125.  
  1126. /*
  1127.  * Can a TIFF image be drawn with this system's version of QuickDraw?
  1128.  */
  1129. Boolean
  1130. TIFFDrawable(TIFFPtr ti)
  1131. {
  1132.     if(ti->samplesPerPixel > 1)
  1133.         return(HasQD32());
  1134.     if(ti->bitsPerSample[0] > 1)
  1135.         return(HasColorQD());
  1136.     return(TRUE);
  1137. }